工艺
Time Limit: 10 Sec Memory Limit: 128 MB
Description
小敏和小燕是一对好朋友。
他们正在玩一种神奇的游戏,叫Minecraft。
他们现在要做一个由方块构成的长条工艺品。但是方块现在是乱的,而且由于机器的要求,他们只能做到把这个工艺品最左边的方块放到最右边。
他们想,在仅这一个操作下,最漂亮的工艺品能多漂亮。
两个工艺品美观的比较方法是,从头开始比较,如果第i个位置上方块不一样那么谁的瑕疵度小,那么谁就更漂亮,如果一样那么继续比较第i+1个方块。如果全都一样,那么这两个工艺品就一样漂亮。
第一行两个整数n,代表方块的数目。
第二行n个整数,每个整数按从左到右的顺序输出方块瑕疵度的值。
Output
一行n个整数,代表最美观工艺品从左到右瑕疵度的值。
10
10 9 8 7 6 5 4 3 2 1
Sample Output
1 10 9 8 7 6 5 4 3 2
HINT
对于100%的数据,n<=300000
Main idea
给定一个环,问从哪一位往后走开始得到的串字典序最小。
Solution
我们先把串复制一遍 ,然后建立一个SAM,然后贪心地走最小的即可。由于SAM的种种奇特♂性质,一定可以走完n个 ,输出即可。由于数字很大,数组不够存,于是我们使用map。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 #include <bits/stdc++.h> using namespace std;const int ONE=1200005 ;const int INF=2147483640 ;map <int ,int > a[ONE]; int n,ch[ONE];int len[ONE],fa[ONE];int get () { int res=1 ,Q=1 ;char c; while ( (c=getchar ())<48 || c>57 ) if (c=='-' )Q=-1 ; res=c-48 ; while ( (c=getchar ())>=48 && c<=57 ) res=res*10 +c-48 ; return res*Q; } struct SAM { int last, cnt; SAM () {last = cnt = 1 ;} void Add (int c) { int x = last, New = last = ++cnt; len[New] = len[x] + 1 ; while (x && !a[x][c]) a[x][c] = New, x = fa[x]; if (!x) {fa[New] = 1 ; return ;} int q = a[x][c]; if (len[q] == len[x] + 1 ) fa[New] = q; else { int Nq = ++cnt; len[Nq] = len[x] + 1 ; a[Nq] = a[q]; fa[Nq] = fa[q]; fa[New] = fa[q] = Nq; while (a[x][c] == q) a[x][c] = Nq, x = fa[x]; } } void Run () { map <int ,int >::iterator it; int x = 1 ; for (int i=1 ; i<=n; i++) { it = a[x].begin (); x = it->second; if (i!=n) printf ("%d " , it->first); else printf ("%d" , it->first); } } }S; int main () { n = get (); for (int i=1 ; i<=n; i++) ch[i] = get (); for (int i=1 ; i<=n*2 ; i++) i<=n ? S.Add (ch[i]):S.Add (ch[i-n]); S.Run (); }